<?php

namespace App\Http\Controllers\Api\Wechat;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class WxBaseController extends Controller
{

    protected $AppId;//APPID

    protected $AppSecret;//APP秘钥

    protected $Mch_id;    //商户号

    protected $Key;//商户号密钥

    //统一下单请求的url
    protected $unifieorder_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';

    //订单查询请求的url
    protected $queryOrder_url = 'https://api.mch.weixin.qq.com/pay/orderquery';

    //订单退款请求url
    protected $refund_url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';

    //初始化数据
    public function __construct()
    {
        $this->AppId = config('services.weixin.client_id');
        $this->AppSecret = config('services.weixin.client_secret');
        $this->Mch_id = config('services.weixin.mch_id');
        $this->Key = config('services.weixin.key');
    }

    //生成签名
    public function getSign($arr)
    {
        //去除空值
        $arr = array_filter($arr);
        if (isset($arr['Sign'])) {
            unset($arr['Sign']);
        }
        //按照键名字典排序
        ksort($arr);
        //生成url格式的字符串
        $str = $this->arrToUrl($arr) . '&key=' . $this->Key;

        return strtoupper(md5($str));
    }

    //获取带签名的数组
    public function setSign($arr)
    {
        $arr['Sign'] = $this->getSign($arr);;
        return $arr;
    }

    //统一下单
    public function unifiedorder($out_trade_no, $money, $notify_url, $openid = '', $body = '购买商品', $type = '')
    {
        $params = [
            'appid' => $this->AppId,
            'mch_id' => $this->Mch_id,
            'nonce_str' => md5(time()),
            'body' => $body,
            'out_trade_no' => $out_trade_no,//订单号
//			'total_fee'        => $money * 100,
            'total_fee' => $money,
            //$_SERVER['REMOTE_ADDR'],
            'spbill_create_ip' => $this->get_client_ip(),
            'notify_url' => $notify_url,
            'trade_type' => 'JSAPI',
            'product_id' => $out_trade_no,
//             'openid'    => $this->getOpenId()
        ];
        if ($type == 'h5') {
            $params['trade_type'] = 'MWEB';
        } else {
            $params['openid'] = $openid;
            if ($openid == '') {
                $params['openid'] = $openid;
            }
        }

        //签名
        $params = $this->setSign($params);

//        Log::info('写入下单参数'.json_encode($params));

        $xmldata = $this->ArrToXml($params);
        $resdata = $this->postXml($this->unifieorder_url, $xmldata);

//         Log::info('写入返回参数'.$resdata);

        //将统一下单接口返回的结果转化成数组
        $arr = $this->XmlToArr($resdata);

        return $arr;
    }

    //获取openid
    public function getOpenId()
    {
        if (isset($_SESSION['openid'])) {
            return $_SESSION['openid'];
        } else {
            //1.用户访问一个地址 先获取到code
            if (!isset($_GET['code'])) {
                //print_r($_SERVER);
                $redurl = $_SERVER['REQUEST_SCHEME'] . 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
                $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" . $this->AppId . "&redirect_uri={$redurl}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
                //构建跳转地址 跳转
                header("location:{$url}");
            } else {
                //2.根据code获取到openid
                //调用接口获取openid
                $openidurl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" . $this->AppId . "&secret=" . $this->AppSecret . "&code=" . $_GET['code'] . "&grant_type=authorization_code";
                $data = file_get_contents($openidurl);
                $arr = json_decode($data, true);
                $_SESSION['openid'] = $arr['openid'];
                return $_SESSION['openid'];
            }
        }
    }


    //调用查询订单接口
    public function queryOrder($oid)
    {
        //构建数据
        $params = [
            'appid' => $this->AppId,
            'mch_id' => $this->Mch_id,
            'out_trade_no' => $oid,
            'nonce_str' => md5(time()),
            'sign_type' => 'MD5'
        ];

        $params = $this->setSign($params);
        $xmldata = $this->ArrToXml($params);

        $resdata = $this->postXml($this->queryOrder_url, $xmldata);
        $arr = $this->XmlToArr($resdata);
        return $arr;
    }


    //获取终端ip
    public function get_client_ip()
    {
        if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
            $ip = getenv('HTTP_CLIENT_IP');
        } elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
            $ip = getenv('HTTP_X_FORWARDED_FOR');
        } elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
            $ip = getenv('REMOTE_ADDR');
        } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        return preg_match('/[\d\.]{7,15}/', $ip, $matches) ? $matches [0] : '';
    }

    //数组转xml
    public function ArrToXml($arr)
    {
        if (!is_array($arr) || count($arr) == 0) {
            return '';
        }

        $xml = "<xml>";
        foreach ($arr as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<  " . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    public function XmlToArr($xml)
    {
        if ($xml == '') {
            return '';
        }

        libxml_disable_entity_loader(true);
        $arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $arr;
    }


    public function postXml($url, $postfields)
    {
        $ch = curl_init();
        //请求url地址
        $params[CURLOPT_URL] = $url;
        //是否返回响应头信息
        $params[CURLOPT_HEADER] = false;
        //是否将结果返回
        $params[CURLOPT_RETURNTRANSFER] = true;
        //是否重定向
        $params[CURLOPT_FOLLOWLOCATION] = true;
        $params[CURLOPT_POST] = true;
        $params[CURLOPT_POSTFIELDS] = $postfields;
        $params[CURLOPT_SSL_VERIFYPEER] = false;
        $params[CURLOPT_SSL_VERIFYHOST] = false;
        //传入curl参数
        curl_setopt_array($ch, $params);
        //执行
        $content = curl_exec($ch);
        //关闭连接
        curl_close($ch);
        return $content;
    }

    public function arrToUrl($arr)
    {
        return urldecode(http_build_query($arr));
    }


    //获取公众号支付所需要的json数据
    public function getJsParams($prepay_id)
    {
        $params = [
            'appId' => $this->AppId,
            'timeStamp' => strval(time()),
            'nonceStr' => md5(time()),
            'package' => 'prepay_id=' . $prepay_id,
            'signType' => 'MD5',
            //       'paySign' => $this->getSign($params)
        ];
        $params['paySign'] = $this->getSign($params);
        return $params;
    }

    public function postXmlCurl($url, $vars, $type, $second = 30, $aHeader = array())
    {
        if ($type == 1) {
            $isdir = getcwd() . '/extend/Wechat/cert/withdrawl/';//证书位置
        } else {
            $isdir = getcwd() . '/extend/Wechat/cert/refund/';//证书位置
        }

        $ch = curl_init();//初始化curl

        curl_setopt($ch, CURLOPT_TIMEOUT, $second);//设置执行最长秒数
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_URL, $url);//抓取指定网页
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);// 终止从服务端进行验证
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);//
        curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');//证书类型
        curl_setopt($ch, CURLOPT_SSLCERT, $isdir . 'apiclient_cert.pem');//证书位置
        curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');//CURLOPT_SSLKEY中规定的私钥的加密类型
        curl_setopt($ch, CURLOPT_SSLKEY, $isdir . 'apiclient_key.pem');//证书位置
        curl_setopt($ch, CURLOPT_CAINFO, 'PEM');
        curl_setopt($ch, CURLOPT_CAINFO, $isdir . 'rootca.pem');
        if (count($aHeader) >= 1) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);//设置头部
        }
        curl_setopt($ch, CURLOPT_POST, 1);//post提交方式
        curl_setopt($ch, CURLOPT_POSTFIELDS, $vars);//全部数据使用HTTP协议中的"POST"操作来发送

        $data = curl_exec($ch);//执行回话
        $error = curl_errno($ch);
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            echo "call faild, errorCode:$error\n";
            curl_close($ch);
            return false;
        }
    }

    public function dotransfer($transfer, &$msg = '')
    {

        $url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";

        $parameters = array(
            'mch_appid' => $this->AppId,//绑定支付的APPID
            'mchid' => $this->Mch_id,//商户号
            'nonce_str' => md5(time()), //生成32位的随机字符串，见图1
            'partner_trade_no' => $transfer['payment_id'],  //商户订单号，不能重复使用
            'openid' => $transfer['open_id'],//用户的open_id
            'check_name' => 'NO_CHECK',//是否检查姓名
            //'re_user_name' => $transfer['real_name'],  //真实姓名
            'amount' => bcmul($transfer['amount'], 100, 0),   //企业付款金额，单位为分  最低1元
            'desc' => '佣金提现',//备注
            'spbill_create_ip' => strval($_SERVER['SERVER_ADDR']),//服务器IP
        );
        $parameters['Sign'] = $this->getSign($parameters, $this->Key);//getSign函数见图2,C('KEY'):商户支付密钥
        $xml = $this->ArrToXml($parameters);//函数见图3
        $response = $this->postXmlCurl($url, $xml, 1);//函数见图4

        $result = $this->XmlToArr($response);//函数见图片5

        if ($result['return_code'] == 'SUCCESS') {
            if ($result['result_code'] == 'SUCCESS') {
                $result['status'] = 1;
                return $result;
            } else {
                $result['status'] = 0;
                return $result;
            }
        } else {
            //echo '付款成功,微信接口异常';
            $result['status'] = 0;
        }
    }

    //微信退款
    public function refund($out_trade_no, $money, $out_refund_no, $refund_fee, $notify_url)
    {
        $params = [
            'appid' => $this->AppId,
            'mch_id' => $this->Mch_id,
            'nonce_str' => md5(time()),
            'out_trade_no' => $out_trade_no,
            'out_refund_no' => $out_refund_no,
            'total_fee' => $money * 100,
            'refund_fee' => $refund_fee,
        ];

        //签名
        $params = $this->setSign($params);
        $xmldata = $this->ArrToXml($params);
        $resdata = $this->postXmlCurl($this->refund_url, $xmldata, 2);
        $result = $this->XmlToArr($resdata);

        if ($result['return_code'] == 'SUCCESS') {
            if ($result['result_code'] == 'SUCCESS') {
                $result['status'] = 1;
                return $result;
            } else {
                $result['status'] = 0;
                return $result;
            }
        } else {
            //echo '付款成功,微信接口异常';
            $result['status'] = 0;
        }
    }
}
